﻿#include "GHash.h"
#include "array/Arrays.h"
#include "lang/System.h"

using namespace yzrilyzr_array;
using namespace yzrilyzr_lang;
namespace yzrilyzr_crypto{
	GHash::GHash(){
		this->H=ByteArray(BLOCK_SIZE);
		this->Y=ByteArray(BLOCK_SIZE);
		reset();
	}
	void GHash::reset(){
		FAQBaseBlockProcessAlgorithm::reset();
		Arrays::fill(Y, (int8_t)0);
		aadBuffer.reset();
		aadProcessed=false;
	}


	ByteArray GHash::processFinalBlock(const ByteArray & incompleteBlock){
		// 应该先确保AAD处理完成
		if(!aadProcessed){
			doFinalAAD();
		}
		// 处理最后一个不完整块
		if(incompleteBlock.length > 0){
			ByteArray block(BLOCK_SIZE);
			Arrays::fill(block, (int8_t)0);
			System::arraycopy(incompleteBlock, 0, block, 0, incompleteBlock.length);
			mProcessBlock(block);
		}
		// 添加长度信息 (AAD长度 || ciphertext长度)
		ByteArray lengths(BLOCK_SIZE);
		longToBytes(aadBuffer.getWriteSize() * 8, lengths, 0);  // AAD长度（位）
		longToBytes(buffer.getWriteSize() * 8, lengths, 8);  // 密文长度（位）
		mProcessBlock(lengths);
		return Arrays::copyOf(Y, BLOCK_SIZE);
	}


	void GHash::processBlock(const ByteArray & block){
		// 应该先确保AAD处理完成
		if(!aadProcessed){
			doFinalAAD();
		}
		mProcessBlock(block);
	}
	yzrilyzr_lang::String GHash::getAlgorithmName()const{
		return "GHash";
	}
	std::shared_ptr<FAQAlgorithm> GHash::newInstance()const{
		return std::make_shared<GHash>();
	}
	void GHash::setKey(const FAQKey & key){
		auto keyBytes=key.getEncoded();
		if(keyBytes.length != BLOCK_SIZE){
			throw IllegalArgumentException("GHash requires a 128-bit key");
		}
		System::arraycopy(keyBytes, 0, H, 0, BLOCK_SIZE);
	}
	u_index GHash::getBlockSize()const{
		return BLOCK_SIZE;
	}
	void GHash::updateAAD(const ByteArray & input){
		updateAAD(input, 0, input.length);
	}
	void GHash::updateAAD(const ByteArray & input, u_index offset, u_index length){
		if(aadProcessed){
			throw IllegalStateException("AAD must be processed before ciphertext");
		}
		aadBuffer.write(input, offset, length);
		while(aadBuffer.available() >= BLOCK_SIZE){
			ByteArray aadBlock(BLOCK_SIZE);
			aadBuffer.read(aadBlock);
			mProcessBlock(aadBlock);
		}
		aadBuffer.compact();
	}

	void GHash::mProcessBlock(const ByteArray & block){
			// 将X和输入块进行异或
		for(int i=0;i < BLOCK_SIZE;i++){
			Y[i]^=block[i];
		}
		// 执行GF(2^128)乘法
		multiplyH();
	}
	/**
	 * GF(2^128)乘法运算 Y = Y • H
	 * 使用Russian peasant算法
	 */
	void GHash::multiplyH(){
		int64_t Y0=bytesToLong(Y, 0);
		int64_t Y1=bytesToLong(Y, 8);
		int64_t H0=bytesToLong(H, 0);
		int64_t H1=bytesToLong(H, 8);
		int64_t Z0=0, Z1=0;
		int64_t V0=H0, V1=H1;
		// 对Y的每一位进行处理
		for(int64_t i=0;i < 128;i++){
			// 检查Y的当前位是否为1
			bool bitSet;
			if(i < 64){
				bitSet=(Y0 & ((int64_t)1 << (63 - i))) != 0;
			} else{
				bitSet=(Y1 & ((int64_t)1 << (127 - i))) != 0;
			}
			if(bitSet){
				Z0^=V0;
				Z1^=V1;
			}
			// 右移V
			bool reduce=(V1 & (int64_t)1) != 0;
			V1=(V0 << 63) | ((uint64_t)V1 >> 1);
			V0=(uint64_t)V0 >> 1;
			if(reduce){
				V0^=REDUCTION_POLYNOMIAL;
			}
		}
		// 将结果存回Y
		longToBytes(Z0, Y, 0);
		longToBytes(Z1, Y, 8);
	}
	int64_t GHash::bytesToLong(const ByteArray & bytes, u_index offset){
		int64_t result=0;
		for(int64_t i=0;i < 8;i++){
			result=(result << 8) | (bytes[offset + i] & 0xFF);
		}
		return result;
	}
	void GHash::longToBytes(int64_t value, const ByteArray & bytes, u_index offset){
		for(int64_t i=7;i >= 0;i--){
			bytes[offset + i]=(int8_t)(value & 0xFF);
			value=((uint64_t)value)>>8;
		}
	}

	void GHash::doFinalAAD(){
		if(aadProcessed) return;
		aadProcessed=true;
		u_index remaining=aadBuffer.available();
		if(remaining > 0){
			ByteArray block(BLOCK_SIZE);
			Arrays::fill(block, (int8_t)0);
			aadBuffer.read(block, 0, remaining);
			mProcessBlock(block);
		}
	}
}